package cn.chenlh.fx.component;

import cn.chenlh.fx.pojo.ListItem;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextField;
import javafx.util.StringConverter;

import java.util.function.Consumer;

/**
 * 可过滤的下拉列表
 */
public class FilteredSelect<V, T extends ListItem<V>> extends ComboBox<T> {
    private final FilteredList<T> filteredItems;
    private final StringConverter<T> stringConverter = new StringConverter<>() {
        @Override
        public String toString(T object) {
            if (object == null) {
                return "";
            }
            return object.getLabel();
        }

        @Override
        public T fromString(String label) {
            for (T item : filteredItems) {
                if (item.getLabel().equals(label)) {
                    return item;
                }
            }
            return null;
        }
    };

    public FilteredSelect(ObservableList<T> items) {
        super(items);
        filteredItems = new FilteredList<>(items, p -> true);
        this.setItems(filteredItems);
        this.setEditable(true);
        this.getEditor().textProperty().addListener(this::onKeyChange);
        this.setConverter(stringConverter);
    }

    public void onSelect(Consumer<V> consumer) {
        this.setOnAction(e -> {
            T value = FilteredSelect.this.getValue();
            V data = value.getData();
            consumer.accept(data);
        });
    }

    private void onKeyChange(ObservableValue<? extends String> observable, String oldValue, String newValue) {
        final TextField editor = FilteredSelect.this.getEditor();
        final T selected = FilteredSelect.this.getSelectionModel().getSelectedItem();
        if (selected == null || !selected.getLabel().equals(editor.getText())) {
            filteredItems.setPredicate(item -> {
                String raw = item.getLabel().toUpperCase();
                String key = newValue.toUpperCase();
                return raw.contains(key);
            });
            FilteredSelect.this.show();
        }
    }
}
